package ttot.transitions.api

import scala.collection
import scala.reflect.runtime.{universe => ru}
import collection.mutable

object Glue extends App {

  val state = mutable.Map[String, Any]()
  val c = new Concrete

  val mirror = ru.runtimeMirror(getClass.getClassLoader)

  def arguments(method: ru.MethodSymbol) = {
    method.paramss.head.map(x => (symbolName(x), x.typeSignature))
  }

  def prepareInvocation[T: ru.TypeTag](t: T, name: String) = {
    val method = ru.typeTag.tpe.declaration(ru.newTermName(name)).asMethod
    val im = mirror.reflect(c)
    val methodMirror = im.reflectMethod(method)
    (methodMirror, arguments(method))
  }

  def invoke[T: ru.TypeTag](t: T, name: String) {
    val info = prepareInvocation(t, name)
    info match {
      case (m, args) => {
        println(m.symbol.name.toString + "(" + args.map(_._1).mkString(", ") + ")")
        val result = m.apply(args.map(x => state(x._1)): _*)
        result match {
          case (left: String, right: Any) => state.put(left, right)
          case r: Map[String, Any] => r.foreach(e => state.put(e._1, e._2))
          case _ =>
        }
        println(state)
      }
    }
  }

  def symbolName(s: ru.Symbol) = {
    val nameOption = s.annotations.filter(_.tpe == ru.typeOf[k]).map(annotationValue(_)).headOption
    nameOption.getOrElse(s.name.toString)
  }

  def annotationValue(a: ru.Annotation) = {
    val value = a.javaArgs.get(ru.newTermName("value")).get.toString
    value.substring(1, value.length - 1)
  }

  invoke(c, "createSession")
  invoke(c, "openLoginPage")
  invoke(c, "login")
  invoke(c, "destroySession")

}
